using System;
using System.Runtime.InteropServices;
using GameBaseCode;

namespace GLWrapper
{
    public class GL
    {
        // not in GL ES
        public static uint GL_MAX_ELEMENTS_VERTICES = 0x80E8;
        public static uint GL_MAX_ELEMENTS_INDICES = 0x80E9;

        public static uint GL_DEPTH_BUFFER_BIT = 0x00000100;
        public static uint GL_COLOR_BUFFER_BIT = 0x00004000;

        /* BeginMode */
        public static uint GL_POINTS = 0x0000;
        public static uint GL_LINES = 0x0001;
        public static uint GL_LINE_LOOP = 0x0002;
        public static uint GL_LINE_STRIP = 0x0003;
        public static uint GL_TRIANGLES = 0x0004;
        public static uint GL_TRIANGLE_STRIP = 0x0005;
        public static uint GL_TRIANGLE_FAN = 0x0006;
        public static uint GL_QUADS = 0x0007; // TODO remove, not in ES.


        /* AlphaFunction */
        public static uint GL_NEVER = 0x0200;
        public static uint GL_LESS = 0x0201;
        public static uint GL_EQUAL = 0x0202;
        public static uint GL_LEQUAL = 0x0203;
        public static uint GL_GREATER = 0x0204;
        public static uint GL_NOTEQUAL = 0x0205;
        public static uint GL_GEQUAL = 0x0206;
        public static uint GL_ALWAYS = 0x0207;
        
        /* BlendingFactorDest */
        public static uint GL_ZERO                           = 0;
        public static uint GL_ONE                            = 1;
        public static uint GL_SRC_COLOR                      = 0x0300;
        public static uint GL_ONE_MINUS_SRC_COLOR            = 0x0301;
        public static uint GL_SRC_ALPHA                      = 0x0302;
        public static uint GL_ONE_MINUS_SRC_ALPHA            = 0x0303;
        public static uint GL_DST_ALPHA                      = 0x0304;
        public static uint GL_ONE_MINUS_DST_ALPHA            = 0x0305;

        /* BlendingFactorSrc */
        /*      GL_ZERO */
        /*      GL_ONE */
        public static uint GL_DST_COLOR = 0x0306;
        public static uint GL_ONE_MINUS_DST_COLOR = 0x0307;
        public static uint GL_SRC_ALPHA_SATURATE = 0x0308;
        /*      GL_SRC_ALPHA */
        /*      GL_ONE_MINUS_SRC_ALPHA */
        /*      GL_DST_ALPHA */
        /*      GL_ONE_MINUS_DST_ALPHA */

        /* CullFaceMode */
        public static uint GL_FRONT = 0x0404;
        public static uint GL_BACK = 0x0405;
        public static uint GL_FRONT_AND_BACK = 0x0408;

        /* EnableCap */
        public static uint GL_FOG                             = 0x0B60;
        public static uint  GL_LIGHTING                       = 0x0B50;
        public static uint  GL_TEXTURE_2D                     = 0x0DE1;
        public static uint  GL_CULL_FACE                      = 0x0B44;
        public static uint  GL_ALPHA_TEST                     = 0x0BC0;
        public static uint  GL_BLEND                          = 0x0BE2;
        public static uint  GL_COLOR_LOGIC_OP                 = 0x0BF2;
        public static uint  GL_DITHER                         = 0x0BD0;
        public static uint  GL_STENCIL_TEST                   = 0x0B90;
        public static uint  GL_DEPTH_TEST                     = 0x0B71;
        /*      GL_LIGHT0 */
        /*      GL_LIGHT1 */
        /*      GL_LIGHT2 */
        /*      GL_LIGHT3 */
        /*      GL_LIGHT4 */
        /*      GL_LIGHT5 */
        /*      GL_LIGHT6 */
        /*      GL_LIGHT7 */
        public static uint  GL_POINT_SMOOTH                   = 0x0B10;
        public static uint  GL_LINE_SMOOTH                    = 0x0B20;
        public static uint  GL_SCISSOR_TEST                   = 0x0C11;
        public static uint  GL_COLOR_MATERIAL                 = 0x0B57;
        public static uint  GL_NORMALIZE                      = 0x0BA1;
        public static uint  GL_RESCALE_NORMAL                 = 0x803A;
        public static uint  GL_POLYGON_OFFSET_FILL            = 0x8037;
        public static uint  GL_VERTEX_ARRAY                   = 0x8074;
        public static uint  GL_NORMAL_ARRAY                   = 0x8075;
        public static uint  GL_COLOR_ARRAY                    = 0x8076;
        public static uint  GL_TEXTURE_COORD_ARRAY            = 0x8078;
        public static uint  GL_MULTISAMPLE                    = 0x809D;
        public static uint  GL_SAMPLE_ALPHA_TO_COVERAGE       = 0x809E;
        public static uint  GL_SAMPLE_ALPHA_TO_ONE            = 0x809F;
        public static uint  GL_SAMPLE_COVERAGE                = 0x80A0;


        /* ErrorCode */
        public const uint GL_NO_ERROR = 0;
        public const uint GL_INVALID_ENUM = 0x0500;
        public const uint GL_INVALID_VALUE = 0x0501;
        public const uint GL_INVALID_OPERATION = 0x0502;
        public const uint GL_STACK_OVERFLOW = 0x0503;
        public const uint GL_STACK_UNDERFLOW = 0x0504;
        public const uint GL_OUT_OF_MEMORY = 0x0505;

        /* LightParameter */
        public static uint GL_AMBIENT = 0x1200;
        public static uint GL_DIFFUSE = 0x1201;
        public static uint GL_SPECULAR = 0x1202;
        public static uint GL_POSITION = 0x1203;
        public static uint GL_SPOT_DIRECTION = 0x1204;
        public static uint GL_SPOT_EXPONENT = 0x1205;
        public static uint GL_SPOT_CUTOFF = 0x1206;
        public static uint GL_CONSTANT_ATTENUATION = 0x1207;
        public static uint GL_LINEAR_ATTENUATION = 0x1208;
        public static uint GL_QUADRATIC_ATTENUATION = 0x1209;

        /* DataType */
        public static uint GL_BYTE = 0x1400;
        public static uint GL_UNSIGNED_BYTE = 0x1401;
        public static uint GL_SHORT = 0x1402;
        public static uint GL_UNSIGNED_SHORT = 0x1403;
        public static uint GL_FLOAT = 0x1406;
        public static uint GL_FIXED = 0x140C;

        /* MaterialFace */
        /*      GL_FRONT_AND_BACK */

        /* MaterialParameter */
        public static uint  GL_EMISSION = 0x1600;
        public static uint  GL_SHININESS = 0x1601;
        public static uint  GL_AMBIENT_AND_DIFFUSE = 0x1602;
        /*      GL_AMBIENT */
        /*      GL_DIFFUSE */
        /*      GL_SPECULAR */


        /* MatrixMode */
        public static uint GL_MODELVIEW = 0x1700;
        public static uint GL_PROJECTION = 0x1701;
        public static uint GL_TEXTURE = 0x1702;

      
        /* PixelFormat */
        public static uint GL_ALPHA = 0x1906;
        public static uint GL_RGB = 0x1907;
        public static uint GL_RGBA = 0x1908;

        /* ShadingModel */
        public static uint GL_FLAT = 0x1D00;
        public static uint GL_SMOOTH = 0x1D01;



/* TexCoordPointerType */
/*      GL_SHORT */
/*      GL_FLOAT */
/*      GL_FIXED */
/*      GL_BYTE */

/* TextureEnvMode */
        public static uint GL_MODULATE = 0x2100;
public static uint GL_DECAL                          = 0x2101;
/*      GL_BLEND */
public static uint GL_ADD                            = 0x0104;
/*      GL_REPLACE */

/* TextureEnvParameter */
public static uint GL_TEXTURE_ENV_MODE               = 0x2200;
public static uint GL_TEXTURE_ENV_COLOR              = 0x2201;

/* TextureEnvTarget */
public static uint GL_TEXTURE_ENV                    = 0x2300;

/* TextureMagFilter */
public static int GL_NEAREST                        = 0x2600;
public static int GL_LINEAR                         = 0x2601;

/* TextureMinFilter */
/*      GL_NEAREST */
/*      GL_LINEAR */
public static uint GL_NEAREST_MIPMAP_NEAREST         = 0x2700;
public static uint GL_LINEAR_MIPMAP_NEAREST          = 0x2701;
public static uint GL_NEAREST_MIPMAP_LINEAR          = 0x2702;
public static uint GL_LINEAR_MIPMAP_LINEAR           = 0x2703;

/* TextureParameterName */
public static uint GL_TEXTURE_MAG_FILTER             = 0x2800;
public static uint GL_TEXTURE_MIN_FILTER             = 0x2801;
public static uint GL_TEXTURE_WRAP_S                 = 0x2802;
public static uint GL_TEXTURE_WRAP_T                 = 0x2803;
public static uint GL_GENERATE_MIPMAP                = 0x8191;

        /* LightName */
        public static uint GL_LIGHT0 = 0x4000;

        /* PolygonMode - not in opengl es!*/
        public static uint GL_POINT = 0x1B00;
        public static uint GL_LINE = 0x1B01;
        public static uint GL_FILL = 0x1B02;

    /* NOT IN GL ES: */
public static uint GL_VIEWPORT                       = 0x0BA2;
public static uint GL_MODELVIEW_MATRIX               = 0x0BA6;
public static uint GL_PROJECTION_MATRIX              = 0x0BA7;
public static uint GL_TEXTURE_MATRIX                 = 0x0BA8;
public static uint GL_DEPTH_RANGE                    = 0x0B70;

        /* GLFW */
        public static int GLFW_WINDOW = 0x00010001;
        public static int GLFW_OPENED = 0x00020001;

public static int GLFW_KEY_SPACE        = 32;
public static int GLFW_KEY_SPECIAL      = 256;
public static int GLFW_KEY_ESC          =(GLFW_KEY_SPECIAL+1);
public static int GLFW_KEY_F1           =(GLFW_KEY_SPECIAL+2);
public static int GLFW_KEY_F2           =(GLFW_KEY_SPECIAL+3);
public static int GLFW_KEY_F3           =(GLFW_KEY_SPECIAL+4);
public static int GLFW_KEY_F4           =(GLFW_KEY_SPECIAL+5);
public static int GLFW_KEY_F5           =(GLFW_KEY_SPECIAL+6);
public static int GLFW_KEY_F6           =(GLFW_KEY_SPECIAL+7);
public static int GLFW_KEY_F7           =(GLFW_KEY_SPECIAL+8);
public static int GLFW_KEY_F8           =(GLFW_KEY_SPECIAL+9);
public static int GLFW_KEY_F9           =(GLFW_KEY_SPECIAL+10);
public static int GLFW_KEY_F10          =(GLFW_KEY_SPECIAL+11);
public static int GLFW_KEY_F11          =(GLFW_KEY_SPECIAL+12);
public static int GLFW_KEY_F12          =(GLFW_KEY_SPECIAL+13);
public static int GLFW_KEY_F13          =(GLFW_KEY_SPECIAL+14);
public static int GLFW_KEY_F14          =(GLFW_KEY_SPECIAL+15);
public static int GLFW_KEY_F15          =(GLFW_KEY_SPECIAL+16);
public static int GLFW_KEY_F16          =(GLFW_KEY_SPECIAL+17);
public static int GLFW_KEY_F17          =(GLFW_KEY_SPECIAL+18);
public static int GLFW_KEY_F18          =(GLFW_KEY_SPECIAL+19);
public static int GLFW_KEY_F19          =(GLFW_KEY_SPECIAL+20);
public static int GLFW_KEY_F20          =(GLFW_KEY_SPECIAL+21);
public static int GLFW_KEY_F21          =(GLFW_KEY_SPECIAL+22);
public static int GLFW_KEY_F22          =(GLFW_KEY_SPECIAL+23);
public static int GLFW_KEY_F23          =(GLFW_KEY_SPECIAL+24);
public static int GLFW_KEY_F24          =(GLFW_KEY_SPECIAL+25);
public static int GLFW_KEY_F25          =(GLFW_KEY_SPECIAL+26);
public static int GLFW_KEY_UP           =(GLFW_KEY_SPECIAL+27);
public static int GLFW_KEY_DOWN         =(GLFW_KEY_SPECIAL+28);
public static int GLFW_KEY_LEFT         =(GLFW_KEY_SPECIAL+29);
public static int GLFW_KEY_RIGHT        =(GLFW_KEY_SPECIAL+30);
public static int GLFW_KEY_LSHIFT       =(GLFW_KEY_SPECIAL+31);
public static int GLFW_KEY_RSHIFT       =(GLFW_KEY_SPECIAL+32);
public static int GLFW_KEY_LCTRL        =(GLFW_KEY_SPECIAL+33);
public static int GLFW_KEY_RCTRL        =(GLFW_KEY_SPECIAL+34);
public static int GLFW_KEY_LALT         =(GLFW_KEY_SPECIAL+35);
public static int GLFW_KEY_RALT         =(GLFW_KEY_SPECIAL+36);
public static int GLFW_KEY_TAB          =(GLFW_KEY_SPECIAL+37);
public static int GLFW_KEY_ENTER        =(GLFW_KEY_SPECIAL+38);
public static int GLFW_KEY_BACKSPACE    =(GLFW_KEY_SPECIAL+39);
public static int GLFW_KEY_INSERT       =(GLFW_KEY_SPECIAL+40);
public static int GLFW_KEY_DEL          =(GLFW_KEY_SPECIAL+41);
public static int GLFW_KEY_PAGEUP       =(GLFW_KEY_SPECIAL+42);
public static int GLFW_KEY_PAGEDOWN     =(GLFW_KEY_SPECIAL+43);
public static int GLFW_KEY_HOME         =(GLFW_KEY_SPECIAL+44);
public static int GLFW_KEY_END          =(GLFW_KEY_SPECIAL+45);
public static int GLFW_KEY_KP_0         =(GLFW_KEY_SPECIAL+46);
public static int GLFW_KEY_KP_1         =(GLFW_KEY_SPECIAL+47);
public static int GLFW_KEY_KP_2         =(GLFW_KEY_SPECIAL+48);
public static int GLFW_KEY_KP_3         =(GLFW_KEY_SPECIAL+49);
public static int GLFW_KEY_KP_4         =(GLFW_KEY_SPECIAL+50);
public static int GLFW_KEY_KP_5         =(GLFW_KEY_SPECIAL+51);
public static int GLFW_KEY_KP_6         =(GLFW_KEY_SPECIAL+52);
public static int GLFW_KEY_KP_7         =(GLFW_KEY_SPECIAL+53);
public static int GLFW_KEY_KP_8         =(GLFW_KEY_SPECIAL+54);
public static int GLFW_KEY_KP_9         =(GLFW_KEY_SPECIAL+55);
public static int GLFW_KEY_KP_DIVIDE    =(GLFW_KEY_SPECIAL+56);
public static int GLFW_KEY_KP_MULTIPLY  =(GLFW_KEY_SPECIAL+57);
public static int GLFW_KEY_KP_SUBTRACT  =(GLFW_KEY_SPECIAL+58);
public static int GLFW_KEY_KP_ADD       =(GLFW_KEY_SPECIAL+59);
public static int GLFW_KEY_KP_DECIMAL   =(GLFW_KEY_SPECIAL+60);
public static int GLFW_KEY_KP_EQUAL     =(GLFW_KEY_SPECIAL+61);
public static int GLFW_KEY_KP_ENTER     =(GLFW_KEY_SPECIAL+62);
public static int GLFW_KEY_KP_NUM_LOCK  =(GLFW_KEY_SPECIAL+63);
public static int GLFW_KEY_CAPS_LOCK    =(GLFW_KEY_SPECIAL+64);
public static int GLFW_KEY_SCROLL_LOCK  =(GLFW_KEY_SPECIAL+65);
public static int GLFW_KEY_PAUSE        =(GLFW_KEY_SPECIAL+66);
public static int GLFW_KEY_LSUPER       =(GLFW_KEY_SPECIAL+67);
public static int GLFW_KEY_RSUPER       =(GLFW_KEY_SPECIAL+68);
public static int GLFW_KEY_MENU         =(GLFW_KEY_SPECIAL+69);
public static int GLFW_KEY_LAST         = GLFW_KEY_MENU;

        public static int GLFW_MOUSE_BUTTON_LEFT   = 0;
        public static int GLFW_MOUSE_BUTTON_RIGHT  = 1;
        public static int GLFW_MOUSE_BUTTON_MIDDLE = 2;


        [DllImport("opengl32")] public static extern void glColor3f(float r, float g, float b);
        [DllImport("opengl32")] public static extern void glColor4f(float r, float g, float b, float a);
        [DllImport("opengl32")] public static extern void glNormal3f(float x, float y, float z);
        [DllImport("opengl32")] public static extern void glVertex3f(float x, float y, float z);
        [DllImport("opengl32")] public static extern void glTexCoord2f(float u, float v);
        [DllImport("opengl32")] public static extern void glClearColor(float r, float g, float b, float alpha);
        [DllImport("opengl32")] public static extern void glClear(uint mask);
        [DllImport("opengl32")] public static extern void glLoadIdentity();
        [DllImport("opengl32")] public static extern void glEnable(uint cap);
        [DllImport("opengl32")] public static extern void glDisable(uint cap);
        [DllImport("opengl32")] public static extern void glEnableClientState(uint array);
        [DllImport("opengl32")] public static extern void glDisableClientState(uint array);
        [DllImport("opengl32")] public static extern void glDrawArrays(uint mode, int first, int count);
        [DllImport("opengl32")] public unsafe static extern void glNormalPointer(uint type, int stride, void* pointer);
        [DllImport("opengl32")] public unsafe static extern void glColorPointer(int size, uint type, int stride, void* pointer);
        [DllImport("opengl32")] public unsafe static extern void glVertexPointer(int size, uint type, int stride, void* pointer);
        [DllImport("opengl32")] public unsafe static extern void glTexCoordPointer(int size, uint type, int stride, void* pointer);
        [DllImport("opengl32")] public unsafe static extern void glDrawElements (uint mode, int count, uint type, void *indices);
        
        [DllImport("opengl32")] public static extern void glTranslatef(float x, float y, float z);
        [DllImport("opengl32")] public static extern void glRotatef(float angle, float x, float y, float z);
        [DllImport("opengl32")] public static extern void glScalef(float x, float y, float z);
        [DllImport("opengl32")] public static extern void glLightfv( uint light, uint pname, float[] lightParam);
        [DllImport("opengl32")] public static extern void glMaterialf(uint face, uint pname, float matParam);
        [DllImport("opengl32")] public static extern void glMaterialfv(uint face, uint pname, float[] matParams);
        [DllImport("opengl32")] public static extern void glColorMaterial(uint face, uint mode);
        [DllImport("opengl32")] public static extern uint glGetError();
        [DllImport("opengl32")] public unsafe static extern void glGetIntegerv(uint pname, int* parameters);
        [DllImport("opengl32")] public static extern void glShadeModel(uint mode);
        [DllImport("opengl32")] public static extern void glCullFace(uint mode);
        [DllImport("opengl32")] public static extern void glMatrixMode(uint mode);
        [DllImport("opengl32")] public static extern void glLoadMatrixf(float[] m);
        [DllImport("opengl32")] public static extern void glMultMatrixf(float[] m);
        [DllImport("opengl32")] public static extern void glPushMatrix();
        [DllImport("opengl32")] public static extern void glPopMatrix();
        [DllImport("opengl32")] public static extern void glBegin(uint mode);
        [DllImport("opengl32")] public static extern void glEnd();
        [DllImport("opengl32")] public static extern void glPointSize(float size);
        [DllImport("opengl32")] public static extern void glPolygonMode(uint faces, uint drawmode);
        [DllImport("opengl32")] public static extern void glFrustum(double left, double right, double bottom, double top, double near, double far);
        [DllImport("opengl32")] public static extern void glOrtho(double left, double right, double bottom, double top, double zNear, double zFar);
        [DllImport("opengl32")] public static extern void glViewport(int x, int y, int width, int height);
        [DllImport("opengl32")] private unsafe static extern void glGenTextures(int n, uint* textures);
        [DllImport("opengl32")] public unsafe static extern void glDeleteTextures(int n, uint* textures );
        [DllImport("opengl32")] public static extern void glBindTexture(uint target, uint texture);
        [DllImport("opengl32")] public unsafe static extern void glTexImage2D(uint target, int level, uint internalformat, int width, int height, int border, uint format, uint type, void* pixels);
        [DllImport("opengl32")] public unsafe static extern void glReadPixels(int x, int y, int width, int height, uint format, uint type, float[] pixels);
        [DllImport("opengl32")] public static extern void glBlendFunc(uint source, uint dest);

//[DllImport("opengl32")] public static extern void glTexEnvf (uint target, uint pname, float param);
//[DllImport("opengl32")] public static extern void glTexEnvfv (uint target, uint pname, float *params);
[DllImport("opengl32")] public static extern void glTexParameterf (uint target, uint pname, float param);
[DllImport("opengl32")] public static extern void glTexParameteri (uint target, uint pname, int param);
//[DllImport("opengl32")] public static extern void glTexParameterfv (GLenum target, GLenum pname, const GLfloat *params);

        [DllImport("opengl32")] public static extern void glLineWidth(float w); // not in GL ES?
        [DllImport("opengl32")] public static extern void glGetDoublev(uint attribute, double[] v);
        [DllImport("opengl32")] public static extern void glGetFloatv(uint attribute, float[] v);

        [DllImport("opengl32")]
        public static extern void glDepthFunc(uint func);
        [DllImport("opengl32")]
        public static extern void glDepthMask(uint flag);

        //[DllImport("opengl32")] public unsafe static extern void glGenBuffers(Int32 n, UInt32* buffers_ptr);
        //[DllImport("opengl32")] public static extern void glBindBuffer(Int32 mode, UInt32 buffer);
        //[DllImport("opengl32")] public unsafe static extern void glBufferData(int target, IntPtr size, IntPtr data, int usage);
        
        
        //public unsafe static void glReadPixels(int x, int y, int width, int height, uint format, uint type, IntPtr pixels)
        //{
        //    glReadPixels(x, y, width, height, format, type, pixels);
        //}

        //public unsafe static void glGenTextures(int n, uint[] textures)
        //{
        //    fixed (uint* p_textures = textures)
        //    {
        //        glGenTextures(n, p_textures);
        //    }
        //}

        public static void glusPerspective(float fovy, float aspect, float nearDist, float farDist)
        {
            float half_height = nearDist * (float)Math.Tan((double)(fovy * 3.14159f / 360.0f));
            float half_width = half_height * aspect;

            glFrustum(-half_width, half_width, -half_height, half_height, nearDist, farDist);
        }

        [DllImport("GLFW")] public static extern int glfwInit();
        [DllImport("GLFW")] public static extern int glfwTerminate();
        [DllImport("GLFW")] public static extern void glfwSwapBuffers();
        [DllImport("GLFW")] public static extern void glfwSleep(double t); [DllImport("GLFW.dll")] public static extern void glfwOpenWindow(int width, int height, int rbits, int gbits, int bbits, int alpha, int depth, int stencil, int mode);
        [DllImport("GLFW")] public static extern int glfwGetWindowParam(int param);
        [DllImport("GLFW")] public unsafe static extern void glfwGetMousePos(int* mx, int* my);
        [DllImport("GLFW")] public static extern int glfwGetKey(int key);
        [DllImport("GLFW")] public static extern int glfwGetMouseButton(int button);        
        [DllImport("GLFW")] public static extern int glfwGetMouseWheel();
        [DllImport("GLFW")] public unsafe static extern void glfwGetWindowSize(int* width, int* height);
        [DllImport("GLFW")] public static extern double glfwGetTime();
        [DllImport("GLFW")] public static extern void glfwSetWindowTitle(char[] title);
        [DllImport("GLFW")] public static extern void glfwSwapInterval(int interval);

        [DllImport("GLFW", CallingConvention = CallingConvention.Cdecl)]
        public static extern void glfwSetKeyCallback(MulticastDelegate callback);

        internal static Matrix4 getProjection()
        {
            float[] projection = new float[16];
            GL.glGetFloatv(GL.GL_PROJECTION_MATRIX, projection);
            Matrix4 res = new Matrix4();
            for (int i = 0; i < 16; i++)
            {
                int r = i % 4;
                int c = i / 4;
                res.m[c, r] = projection[i];
            }
            return res;
        }

        internal static Matrix4 model_view()
        {
            float[] modelView = new float[16];
            GL.glGetFloatv(GL.GL_MODELVIEW_MATRIX, modelView);
            Matrix4 res = new Matrix4();
            for (int i = 0; i < 16; i++)
            {
                int r = i % 4;
                int c = i / 4;
                res.m[c, r] = modelView[i];
            }
            return res;
        }

        public static void DrawCircle2D(float r)
        {
            glBegin(GL_LINE_STRIP);
            for (int i = 0; i < 18; i++)
            {
                float ang = i * 6.28381f / 17.0f;
                float xp = r * (float)Math.Cos(ang);
                float zp = r * (float)Math.Sin(ang);
                glVertex3f(xp, zp, 0);
            }
            glEnd();
        }

        public static void DrawCircle(float r)
        {
            glBegin(GL_LINE_STRIP);
            for(int i=0; i<18; i++)
            {
                float ang = i * 6.28381f / 17.0f;
                float xp = r * (float)Math.Cos(ang);
                float zp = r * (float)Math.Sin(ang);
	            glVertex3f(xp,0,zp);
            }
            glEnd();
        }

        public static void DrawWireSphere(float radius)
        {
            glPolygonMode(GL.GL_FRONT_AND_BACK, GL.GL_LINE);
            DrawSphere(radius, 8, 8);
            glPolygonMode(GL.GL_FRONT_AND_BACK, GL.GL_FILL);
        }

        public static void DrawSphere(float fRadius, int iSlices, int iStacks)
        {
            float drho = (float)(3.141592653589) / (float)iStacks;
            float dtheta = 2.0f * (float)(3.141592653589) / (float)iSlices;
            float ds = 1.0f / (float)iSlices;
            float dt = 1.0f / (float)iStacks;
            float t = 1.0f;
            float s = 0.0f;
            int i, j;     // Looping variables

            for (i = 0; i < iStacks; i++)
            {
                float rho = (float)i * drho;
                float srho = (float)(Math.Sin(rho));
                float crho = (float)(Math.Cos(rho));
                float srhodrho = (float)(Math.Sin(rho + drho));
                float crhodrho = (float)(Math.Cos(rho + drho));

                // Many sources of OpenGL sphere drawing code uses a triangle fan
                // for the caps of the sphere. This however introduces texturing 
                // artifacts at the poles on some OpenGL implementations
                GL.glBegin(GL.GL_TRIANGLE_STRIP);
                s = 0.0f;
                for (j = 0; j <= iSlices; j++)
                {
                    float theta = (j == iSlices) ? 0.0f : j * dtheta;
                    float stheta = (float)(-Math.Sin(theta));
                    float ctheta = (float)(Math.Cos(theta));

                    float x = stheta * srho;
                    float y = ctheta * srho;
                    float z = crho;

                    GL.glTexCoord2f(s, t);
                    GL.glNormal3f(x, y, z);
                    GL.glVertex3f(x * fRadius, y * fRadius, z * fRadius);

                    x = stheta * srhodrho;
                    y = ctheta * srhodrho;
                    z = crhodrho;
                    GL.glTexCoord2f(s, t - dt);
                    s += ds;
                    GL.glNormal3f(x, y, z);
                    GL.glVertex3f(x * fRadius, y * fRadius, z * fRadius);
                }
                GL.glEnd();

                t -= dt;
            }
        }

        public static void DrawCube()
        {
            GL.glEnableClientState(GL.GL_VERTEX_ARRAY);

            float[] kube = {1,1,1,  -1,1,1,  -1,-1,1,  1,-1,1,              // v0-v1-v2-v3
                                  1,1,1,  1,-1,1,  1,-1,-1,  1,1,-1,        // v0-v3-v4-v5
                                  1,1,1,  1,1,-1,  -1,1,-1,  -1,1,1,        // v0-v5-v6-v1
                                  -1,1,1,  -1,1,-1,  -1,-1,-1,  -1,-1,1,    // v1-v6-v7-v2
                                  -1,-1,-1,  1,-1,-1,  1,-1,1,  -1,-1,1,    // v7-v4-v3-v2
                                  1,-1,-1,  -1,-1,-1,  -1,1,-1,  1,1,-1};   // v4-v7-v6-v5
            unsafe
            {

                fixed (float* ptr = &kube[0])
                    GL.glVertexPointer(3, GL.GL_FLOAT, 0, ptr);
            }
            GL.glDrawArrays(GL.GL_QUADS, 0, 24);
            GL.glDisableClientState(GL.GL_VERTEX_ARRAY);
        }

        public static void DrawCubeFace(int face)
        {
            GL.glEnableClientState(GL.GL_TEXTURE_COORD_ARRAY);
            GL.glEnableClientState(GL.GL_VERTEX_ARRAY);

            float[] coords = {   0,1, 1,1, 1,0, 0,0, // +Z
                                 0,1, 0,0, 1,0, 1,1, // +X 
                                 0,0, 1,0, 1,1, 0,1, //
                                 1,1, 0,1, 0,0, 1,0, // -X
                                 0,0, 1,0, 1,1, 0,1,
                                 0,0, 1,0, 1,1, 0,1 // -Z 
                             };

            float[] kube = {1,1,1,  -1,1,1,  -1,-1,1,  1,-1,1,        //0: v0-v1-v2-v3 +Z front 
                                  1,1,1,  1,-1,1,  1,-1,-1,  1,1,-1,        //1: v0-v3-v4-v5 +X right 
                                  1,1,1,  1,1,-1,  -1,1,-1,  -1,1,1,        //2: v0-v5-v6-v1 +Y top   
                                  -1,1,1,  -1,1,-1,  -1,-1,-1,  -1,-1,1,    //3: v1-v6-v7-v2 -X left  
                                  -1,-1,-1,  1,-1,-1,  1,-1,1,  -1,-1,1,    //4: v7-v4-v3-v2 -Y bottom
                                  1,-1,-1,  -1,-1,-1,  -1,1,-1,  1,1,-1};   //5: v4-v7-v6-v5 -Z back
            unsafe
            {

                fixed (float* ptr = &kube[0])
                    GL.glVertexPointer(3, GL.GL_FLOAT, 0, ptr);

                fixed (float* ptr = &coords[0])
                    GL.glTexCoordPointer(2, GL.GL_FLOAT, 0, ptr);
            }
            GL.glDrawArrays(GL.GL_QUADS, face*4, 4);
            GL.glDisableClientState(GL.GL_VERTEX_ARRAY);
            GL.glDisableClientState(GL.GL_TEXTURE_COORD_ARRAY);
        }

        public static void glTranslate(Vector3 v)
        {
            glTranslatef(v.x, v.y, v.z);
        }
        public static void glVertex(Vector3 v)
        {
            glVertex3f(v.x, v.y, v.z);
        }
        public static void glColor(Vector3 v)
        {
            glColor3f(v.x, v.y, v.z);
        }
        

        public static void DrawRect(int xp, int yp, int w, int h)
        {
            float eps = 1e-4f;
            glBegin(GL_QUADS);
            glTexCoord2f(0, 0); glVertex3f( xp, yp, -eps);
            glTexCoord2f(0, 1); glVertex3f( xp, yp + h, -eps);
            glTexCoord2f(1, 1); glVertex3f( xp + w, yp + h, -eps);
            glTexCoord2f(1, 0); glVertex3f( xp + w,  yp, -eps);
            glEnd();
        }

        public static void DrawRectOpen(int xp, int yp, int w, int h)
        {
            glBegin(GL_LINE_LOOP);
            glVertex3f(xp, yp, -.1f);
            glVertex3f(xp, yp + h, -.1f);
            glVertex3f(xp + w, yp + h, -.1f);
            //glVertex3f(xp + w, yp, -.1f);
            glEnd();
        }


        public static void get_gl_errors()
        {
            uint err;
            while ((err = GL.glGetError()) != GL.GL_NO_ERROR)
            {
                switch (err)
                {
                    case GL.GL_INVALID_ENUM:
                        Console.WriteLine("GL_INVALID_ENUM, did you type GL_BEGIN(GL_LINE), instead of GL_LINES? GL_AMBIENT_AND_DIFFUSE instead of GL_DIFFUSE or GL_AMBIENT in LIGHTF?");
                        break;
                    case GL.GL_INVALID_VALUE:
                        Console.WriteLine("GL_INVALID_VALUE, did you pass float where and int was expected?");
                        break;
                    case GL.GL_INVALID_OPERATION:
                        Console.WriteLine("GL_INVALID_OPERATION");
                        break;
                    case GL.GL_STACK_OVERFLOW:
                        Console.WriteLine("GL_STACK_OVERFLOW, stray push?");
                        break;
                    case GL.GL_STACK_UNDERFLOW:
                        Console.WriteLine("GL_STACK_UNDERFLOW, stray pop?");
                        break;
                    case GL.GL_OUT_OF_MEMORY:
                        Console.WriteLine("GL_OUT_OF_MEMORY");
                        break;
                    default:
                        Console.WriteLine("unknow gl error");
                        break;
                }

                err = GL.glGetError();
            }
        }



        public static void glMultMatrix(Matrix3 frame)
        {
            //float[] glmatrix = new float[16];
            //for (int i = 0; i < 4; i++)
            //{
            //    for (int j = 0; j < 4; j++)
            //    {
            //        glmatrix[i * 4 + j] = modelview.m[i, j];
            //    }
            //}

                                     //Mat4f mtx( 
                                     //   Vec4f( right[0], right[1], right[2], 0.0f), 
                                     //   Vec4f( upward[0], upward[1], upward[2], 0.0f), 
                                     //   Vec4f( forward[0], forward[1], forward[2], 0.0f), 
                                     //   Vec4f( 0.0f, 0.0f, 0.0f, 1.0f) 
                                     //   );

            float[] mtx = 
            {
                frame[0], frame[1], frame[2], 0.0f,
                frame[3], frame[4], frame[5], 0.0f,
                frame[6], frame[7], frame[8], 0.0f,
                0.0f,0.0f,0.0f, 1.0f
            };
            if (mtx.Length != 16) throw new Exception("wird");
            glMultMatrixf(mtx);
        }
    } // eof class GL
} // eof glWrapper